Skip to content

peer: bound peer-controlled resource growth - #11090

Open
yyforyongyu wants to merge 6 commits into
lightningnetwork:masterfrom
yyforyongyu:task-peer-manager
Open

peer: bound peer-controlled resource growth#11090
yyforyongyu wants to merge 6 commits into
lightningnetwork:masterfrom
yyforyongyu:task-peer-manager

Conversation

@yyforyongyu

Copy link
Copy Markdown
Member

Change Description

Bound the resources a peer can consume through inbound pings and queued
outgoing messages.

Inbound ping handling now has two limits:

  • Pong replies are limited to one per second with a burst of 20. Pings above
    that reply budget are accepted without a Pong.
  • Peers exceeding ten pings per second with a burst of 200 are disconnected.
    This flood check also covers pings whose requested Pong size would otherwise
    be ignored.

The per-peer outgoing backlog is also capped at 10,000 messages and 16 MiB of
charged memory. Queue accounting covers fixed overhead and the high-risk
dynamic payloads without serializing messages on the hot path. An overflowing
peer is disconnected while the queue remains serviced until teardown, avoiding
deadlocks with synchronous senders.

Release notes are included for 0.21.3 and 0.20.4.

Open Question

The reply budget deliberately deviates from BOLT 1's requirement to answer
valid pings. A peer using those pings for liveness may close the connection when
its Pong is skipped, so the 1-10 ping/second band can relocate the disconnect
decision to the remote peer and make lnd appear unresponsive. Should the two
tiers remain, or should they be collapsed into the flood disconnect threshold?
This draft implements both tiers so reviewers can evaluate the concrete
behavior.

Steps to Test

GOWORK=off go build ./peer/... ./lnwire/...
GOWORK=off go test ./peer/
GOWORK=off go test -race ./peer/
GOWORK=off go vet ./peer/
GOGC=50 make lint

The queue-accounting and teardown-drain regression tests were also mutation
tested by removing their respective implementation lines and confirming each
test failed.

Pull Request Checklist

Testing

  • Your PR passes all CI checks.
  • Tests covering the positive and negative (error paths) are included.
  • Bug fixes contain tests triggering the bug to prevent regressions.

Code Style and Documentation

  • The change is not insubstantial.
  • The change obeys the documentation and 80-column guidelines.
  • Commits follow the ideal Git commit structure.
  • New logging statements use appropriate levels.
  • No lncli commands are added.
  • Release-note entries are included.

@github-actions github-actions Bot added the severity-critical Requires expert review - security/consensus critical label Aug 17, 2026
@github-actions

Copy link
Copy Markdown

🔴 PR Severity: CRITICAL

file classification | 4 files | 500 lines changed

🔴 Critical (1 file)
  • peer/brontide.go - modifies peer connection resource-limiting logic (ping/pong flood protection, outgoing message queue caps) in the brontide encrypted-transport layer
🟢 Low (3 files)
  • peer/brontide_test.go - test-only change
  • docs/release-notes/release-notes-0.20.4.md - release notes
  • docs/release-notes/release-notes-0.21.3.md - release notes

Analysis

The substantive change is entirely in peer/brontide.go, which falls under the peer/*/brontide/* critical category (encrypted peer connections). It adds new resource-bounding logic for inbound pings (rate limiting, flood-based disconnects) and the outgoing message queue (size/memory caps with disconnect-on-overflow), directly affecting peer connection liveness and DoS resistance. No bump conditions apply (only 2 non-test files changed, ~194 non-test lines changed, single critical package touched). This is exactly the kind of peer-protocol change that warrants expert review, and the PR author itself flags an open design question about ping/pong disconnect semantics deviating from BOLT 1.


To override, add a severity-override-{critical,high,medium,low} label.

@yyforyongyu yyforyongyu added backport-v0.20.x-branch This label is used to trigger the creation of a backport PR to the branch `v0.20.x-branch`. backport-v0.21.x-branch This label triggers a backport to branch `v0.21.x-branch ` labels Aug 19, 2026
@yyforyongyu yyforyongyu self-assigned this Aug 19, 2026
@yyforyongyu yyforyongyu added this to the v0.21.3 milestone Aug 19, 2026
@yyforyongyu
yyforyongyu marked this pull request as ready for review August 19, 2026 13:28
Comment thread peer/brontide.go Outdated

// pongReplyLimiter and pingFloodLimiter enforce the two-tier inbound
// ping policy for this connection.
pongReplyLimiter *rate.Limiter

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just name it pongLimiter and pingLimiter?

Comment thread peer/brontide.go Outdated
// outgoingMsg interface box, and list element, which we round up here.
// Charging this overhead makes cheap-message floods visible to the byte
// budget instead of treating shared Pong payloads as free.
queuedMsgOverhead = 128

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all these consts are flying around, i wonder if we could turn them into a struct or config

Comment thread peer/brontide.go
}
popMsg(front)
case msg := <-p.outgoingQueue:
if msg.priority {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if we should stop modifying this loop? feels like a layer violation as the abstraction is broken? the queuing layer should not be aware of the ping/pong context?

@yyforyongyu
yyforyongyu marked this pull request as draft August 19, 2026 22:58
Bound Pong replies with separate reply and flood token buckets while
disconnecting peers that exhaust the flood budget. Add deterministic
coverage for honest cadences, reply suppression, and flood teardown.
Collect the count, retained-memory, and fixed-overhead thresholds in one
private policy value. Keep wire-specific cost estimation with that policy so
the generic queue does not need Ping or Pong knowledge.
Calculate retained-memory charges when outgoing messages enter the peer
queue boundary and carry the result as immutable metadata. Add a generic
priority queue that accounts with those charges instead of inspecting wire
message types.
Route queueHandler through the bounded queue abstraction and disconnect
when either the count or retained-memory budget is exceeded. Use one
nil-gated send case for empty and non-empty states, and keep servicing
producers during teardown so disconnect cannot deadlock.
Cover count and retained-memory overflow, cost accounting, healthy queue
draining, and sender service during teardown. The focused cases exercise
the production queue boundary without starting unrelated peer loops.
Document the ping reply rate and outgoing queue bounds in both supported
patch release notes so operators know that peer-controlled resource
exhaustion is mitigated.
@yyforyongyu
yyforyongyu marked this pull request as ready for review August 19, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-v0.20.x-branch This label is used to trigger the creation of a backport PR to the branch `v0.20.x-branch`. backport-v0.21.x-branch This label triggers a backport to branch `v0.21.x-branch ` severity-critical Requires expert review - security/consensus critical

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant